From 23e35706b49c0266765f5de017c206db40a062b1 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Dec 2016 21:59:28 +0100 Subject: [PATCH] gsk: Add support for rounded clip rectangles Also add support to GtkSnapshot, so people can push rounded clips. --- docs/reference/gsk/gsk4-sections.txt | 2 + docs/reference/gtk/gtk4-sections.txt | 1 + gsk/gskrendernode.h | 7 ++ gsk/gskrendernodeimpl.c | 124 +++++++++++++++++++++++++ gsk/gskrendernodeprivate.h | 2 + gtk/gtksnapshot.c | 68 ++++++++++++++ gtk/gtksnapshot.h | 5 + gtk/inspector/gtktreemodelrendernode.c | 4 + 8 files changed, 213 insertions(+) diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 5ea9fbd339..a12c28d938 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -47,6 +47,8 @@ gsk_opacity_node_new gsk_opacity_node_get_child gsk_clip_node_new gsk_clip_node_get_child +gsk_rounded_clip_node_new +gsk_rounded_clip_node_get_child GSK_IS_RENDER_NODE GSK_RENDER_NODE diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index bab84761be..e0a3f560bd 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4457,6 +4457,7 @@ gtk_snapshot_push gtk_snapshot_push_node gtk_snapshot_push_transform gtk_snapshot_push_clip +gtk_snapshot_push_rounded_clip gtk_snapshot_pop gtk_snapshot_pop_and_append gtk_snapshot_set_transform diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index cdd52b7cb0..708a77dbbe 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -23,6 +23,7 @@ #error "Only can be included directly." #endif +#include #include G_BEGIN_DECLS @@ -85,6 +86,12 @@ GskRenderNode * gsk_clip_node_new (GskRenderNode GDK_AVAILABLE_IN_3_90 GskRenderNode * gsk_clip_node_get_child (GskRenderNode *node); +GDK_AVAILABLE_IN_3_90 +GskRenderNode * gsk_rounded_clip_node_new (GskRenderNode *child, + const GskRoundedRect *clip); +GDK_AVAILABLE_IN_3_90 +GskRenderNode * gsk_rounded_clip_node_get_child (GskRenderNode *node); + GDK_AVAILABLE_IN_3_90 void gsk_render_node_set_blend_mode (GskRenderNode *node, GskBlendMode blend_mode); diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index 9797f23c9d..9dbfd3f23d 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -20,6 +20,7 @@ #include "gskdebugprivate.h" #include "gskrendererprivate.h" +#include "gskroundedrectprivate.h" #include "gsktextureprivate.h" /*** GSK_COLOR_NODE ***/ @@ -944,3 +945,126 @@ gsk_clip_node_peek_clip (GskRenderNode *node) return &self->clip; } +/*** GSK_ROUNDED_CLIP_NODE ***/ + +typedef struct _GskRoundedClipNode GskRoundedClipNode; + +struct _GskRoundedClipNode +{ + GskRenderNode render_node; + + GskRenderNode *child; + GskRoundedRect clip; +}; + +static void +gsk_rounded_clip_node_finalize (GskRenderNode *node) +{ + GskRoundedClipNode *self = (GskRoundedClipNode *) node; + + gsk_render_node_unref (self->child); +} + +static void +gsk_rounded_clip_node_make_immutable (GskRenderNode *node) +{ + GskRoundedClipNode *self = (GskRoundedClipNode *) node; + + gsk_render_node_make_immutable (self->child); +} + +static void +gsk_rounded_clip_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskRoundedClipNode *self = (GskRoundedClipNode *) node; + + cairo_save (cr); + + gsk_rounded_rect_path (&self->clip, cr); + cairo_clip (cr); + + gsk_render_node_draw (self->child, cr); + + cairo_restore (cr); +} + +static void +gsk_rounded_clip_node_get_bounds (GskRenderNode *node, + graphene_rect_t *bounds) +{ + GskRoundedClipNode *self = (GskRoundedClipNode *) node; + graphene_rect_t child_bounds; + + gsk_render_node_get_bounds (self->child, &child_bounds); + + graphene_rect_intersection (&self->clip.bounds, &child_bounds, bounds); +} + +static const GskRenderNodeClass GSK_ROUNDED_CLIP_NODE_CLASS = { + GSK_ROUNDED_CLIP_NODE, + sizeof (GskRoundedClipNode), + "GskRoundedClipNode", + gsk_rounded_clip_node_finalize, + gsk_rounded_clip_node_make_immutable, + gsk_rounded_clip_node_draw, + gsk_rounded_clip_node_get_bounds +}; + +/** + * gsk_rounded_clip_node_new: + * @child: The node to draw + * @clip: The clip to apply + * + * Creates a #GskRenderNode that will clip the @child to the area + * given by @clip. + * + * Returns: A new #GskRenderNode + * + * Since: 3.90 + */ +GskRenderNode * +gsk_rounded_clip_node_new (GskRenderNode *child, + const GskRoundedRect *clip) +{ + GskRoundedClipNode *self; + + g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL); + g_return_val_if_fail (clip != NULL, NULL); + + self = (GskRoundedClipNode *) gsk_render_node_new (&GSK_ROUNDED_CLIP_NODE_CLASS); + + self->child = gsk_render_node_ref (child); + gsk_rounded_rect_init_copy (&self->clip, clip); + + return &self->render_node; +} + +/** + * gsk_rounded_clip_node_get_child: + * @node: a clip @GskRenderNode + * + * Gets the child node that is getting clipped by the given @node. + * + * Returns: (transfer none): The child that is getting clipped + **/ +GskRenderNode * +gsk_rounded_clip_node_get_child (GskRenderNode *node) +{ + GskRoundedClipNode *self = (GskRoundedClipNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_ROUNDED_CLIP_NODE), NULL); + + return self->child; +} + +const GskRoundedRect * +gsk_rounded_clip_node_peek_clip (GskRenderNode *node) +{ + GskRoundedClipNode *self = (GskRoundedClipNode *) node; + + g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_ROUNDED_CLIP_NODE), NULL); + + return &self->clip; +} + diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 1bb06394cf..98f8fc35a6 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -62,6 +62,8 @@ const GdkRGBA *gsk_color_node_peek_color (GskRenderNode *node); const graphene_rect_t * gsk_clip_node_peek_clip (GskRenderNode *node); +const GskRoundedRect * gsk_rounded_clip_node_peek_clip (GskRenderNode *node); + void gsk_transform_node_get_transform (GskRenderNode *node, graphene_matrix_t *transform); GskBlendMode gsk_render_node_get_blend_mode (GskRenderNode *node); diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 663fd582c3..4f05586269 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -352,6 +352,74 @@ gtk_snapshot_push_clip (GtkSnapshot *snapshot, cairo_region_destroy (clip); } +static GskRenderNode * +gtk_snapshot_collect_rounded_clip (GskRenderNode **nodes, + guint n_nodes, + const char *name, + gpointer bounds) +{ + GskRenderNode *node, *clip_node; + + node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL); + if (node == NULL) + return NULL; + + clip_node = gsk_rounded_clip_node_new (node, bounds); + gsk_render_node_set_name (clip_node, name); + + gsk_render_node_unref (node); + g_slice_free (GskRoundedRect, bounds); + + return clip_node; +} + +void +gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot, + const GskRoundedRect *bounds, + const char *name, + ...) +{ + GskRoundedRect *real_bounds; + cairo_region_t *clip; + cairo_rectangle_int_t rect; + char *str; + + real_bounds = g_slice_new (GskRoundedRect); + gsk_rounded_rect_init_copy (real_bounds, bounds); + gsk_rounded_rect_offset (real_bounds, snapshot->state->translate_x, snapshot->state->translate_y); + + if (name) + { + va_list args; + + va_start (args, name); + str = g_strdup_vprintf (name, args); + va_end (args); + } + else + str = NULL; + + rectangle_init_from_graphene (&rect, &real_bounds->bounds); + if (snapshot->state->clip_region) + { + clip = cairo_region_copy (snapshot->state->clip_region); + cairo_region_intersect_rectangle (clip, &rect); + } + else + { + clip = cairo_region_create_rectangle (&rect); + } + snapshot->state = gtk_snapshot_state_new (snapshot->state, + str, + clip, + snapshot->state->translate_x, + snapshot->state->translate_y, + gtk_snapshot_collect_rounded_clip, + real_bounds); + + cairo_region_destroy (clip); +} + /** * gtk_snapshot_pop: * @snapshot: a #GtkSnapshot diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h index 5f4bb4b474..ea9c578ad3 100644 --- a/gtk/gtksnapshot.h +++ b/gtk/gtksnapshot.h @@ -52,6 +52,11 @@ void gtk_snapshot_push_clip (GtkSnapshot const char *name, ...) G_GNUC_PRINTF (3, 4); GDK_AVAILABLE_IN_3_90 +void gtk_snapshot_push_rounded_clip (GtkSnapshot *snapshot, + const GskRoundedRect *bounds, + const char *name, + ...) G_GNUC_PRINTF (3, 4); +GDK_AVAILABLE_IN_3_90 GskRenderNode * gtk_snapshot_pop (GtkSnapshot *snapshot) G_GNUC_WARN_UNUSED_RESULT; GDK_AVAILABLE_IN_3_90 void gtk_snapshot_pop_and_append (GtkSnapshot *snapshot); diff --git a/gtk/inspector/gtktreemodelrendernode.c b/gtk/inspector/gtktreemodelrendernode.c index c44c4c7e0e..ce470ee9df 100644 --- a/gtk/inspector/gtktreemodelrendernode.c +++ b/gtk/inspector/gtktreemodelrendernode.c @@ -538,6 +538,10 @@ append_node (GtkTreeModelRenderNode *nodemodel, append_node (nodemodel, gsk_clip_node_get_child (node), priv->nodes->len - 1); break; + case GSK_ROUNDED_CLIP_NODE: + append_node (nodemodel, gsk_rounded_clip_node_get_child (node), priv->nodes->len - 1); + break; + case GSK_CONTAINER_NODE: { gint elt_index; -- 2.30.2